home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / hydracom.lha / source / amiga.c < prev    next >
C/C++ Source or Header  |  1995-08-16  |  56KB  |  2,593 lines

  1. /*
  2. **    Amiga support module for HYDRA protocol sample implementation.
  3. **
  4. **    Written by    Olaf Barthel
  5. **            Brabeckstrasse 35
  6. **            D-30559 Hannover
  7. **
  8. **            eMail: olsen@sourcery.han.de
  9. **
  10. **    Freely distributable.
  11. */
  12.  
  13.     /* System includes. */
  14.  
  15. #include <intuition/intuitionbase.h>
  16.  
  17. #include <libraries/gadtools.h>
  18. #include <libraries/locale.h>
  19. #include <libraries/asl.h>
  20.  
  21. #include <graphics/gfxbase.h>
  22.  
  23. #include <utility/date.h>
  24.  
  25. #include <devices/conunit.h>
  26. #include <devices/serial.h>
  27. #include <devices/timer.h>
  28.  
  29. #include <hardware/cia.h>
  30.  
  31. #include <dos/dosextens.h>
  32. #include <dos/filehandler.h>
  33. #include <dos/dostags.h>
  34. #include <dos/dosasl.h>
  35.  
  36. #include <exec/memory.h>
  37.  
  38.     /* Correct a nasty bug in the prototypes. */
  39.  
  40. #define CheckIO foo21234
  41.  
  42. #include <clib/intuition_protos.h>
  43. #include <clib/gadtools_protos.h>
  44. #include <clib/graphics_protos.h>
  45. #include <clib/utility_protos.h>
  46. #include <clib/locale_protos.h>
  47. #include <clib/timer_protos.h>
  48. #include <clib/exec_protos.h>
  49. #include <clib/dos_protos.h>
  50. #include <clib/asl_protos.h>
  51. #include <clib/macros.h>
  52.  
  53. #include <errno.h>
  54.  
  55. //#define DB(x)    x
  56. #define DB(x)
  57.  
  58. void __stdargs kprintf(STRPTR,...);
  59.  
  60.     /* Get the CheckIO prototype right. */
  61.  
  62. #undef CheckIO
  63.  
  64. struct IORequest *CheckIO(struct IORequest *);
  65.  
  66. #include "Rendezvous.h"
  67.  
  68. #include "hydracom.h"
  69.  
  70.     /* Difference between UTC and Amiga time. */
  71.  
  72. #define UTC_OFFSET    252482400
  73.  
  74.     /* Minimum of lines to reserve for local input. */
  75.  
  76. #define MIN_LINES    3
  77.  
  78.     /* Serial buffer size. */
  79.  
  80. #define BUFFER_SIZE    8192
  81.  
  82.     /* A handy macro. */
  83.  
  84. #define ClrSignal(s)    SetSignal(0,s)
  85.  
  86.     /* Signal masks. */
  87.  
  88. #define SIG_SERREAD    (1UL << ReadPort -> mp_SigBit)
  89. #define SIG_SERWRITE    (1UL << WritePort -> mp_SigBit)
  90. #define SIG_CONREAD    (1UL << ConsoleReadPort -> mp_SigBit)
  91. #define SIG_TIMER    (1UL << TimePort -> mp_SigBit)
  92. #define SIG_WINDOW    (1UL << WindowPort -> mp_SigBit)
  93. #define SIG_HANDSHAKE    SIGF_SINGLE
  94. #define SIG_KILL    SIGBREAKF_CTRL_C
  95.  
  96.     /* A serial buffer structure. */
  97.  
  98. struct SerialBuffer
  99. {
  100.     struct IOExtSer    *SerialRequest;
  101.     UBYTE        *SerialBuffer,
  102.             *SerialIndex,
  103.             *SerialTop;
  104.     LONG         SerialSize,
  105.              SerialFilled;
  106.     BOOL         IsClone,
  107.              IsBusy;
  108. };
  109.  
  110.     /* Special rendezvous data. */
  111.  
  112. STATIC struct RendezvousData        *RendezvousData;
  113. STATIC struct RendezvousSemaphore    *RendezvousSemaphore;
  114.  
  115.     /* Library bases. */
  116.  
  117. struct IntuitionBase    *IntuitionBase;
  118. struct GfxBase        *GfxBase;
  119. struct LocaleBase    *LocaleBase;
  120. struct Library        *GadToolsBase,
  121.             *UtilityBase,
  122.             *TimerBase,
  123.             *AslBase;
  124.  
  125.     /* Timer data. */
  126.  
  127. struct MsgPort        *TimePort;
  128. struct timerequest    *TimeRequest;
  129.  
  130.     /* Serial data. */
  131.  
  132. struct MsgPort        *ReadPort,
  133.             *WritePort;
  134.  
  135. struct SerialBuffer    *ThisBuffer,
  136.             *NextBuffer,
  137.             *ReadBuffer;
  138.  
  139.     /* Console data. */
  140.  
  141. struct MsgPort        *WindowPort;
  142.  
  143. struct Window        *FileWindow,
  144.             *RemoteWindow,
  145.             *LocalWindow,
  146.             *LogWindow;
  147.  
  148. struct MsgPort        *ConsoleWritePort,
  149.             *ConsoleReadPort;
  150. struct IOStdReq        *ConsoleReadRequest;
  151. UBYTE             ConsoleChar;
  152. BOOL             ConsoleReady = FALSE,
  153.              WindowReady = FALSE;
  154.  
  155. struct IOStdReq        *FileRequest,
  156.             *RemoteRequest,
  157.             *LocalRequest,
  158.             *LogRequest;
  159.  
  160.     /* DOS Data. */
  161.  
  162. struct Process        *ThisProcess;
  163. APTR             OldPtr;
  164. LONG             OldPri;
  165.  
  166. struct AnchorPath    *Anchor;
  167. BOOL             AnchorUsed = FALSE;
  168.  
  169.     /* File requester data. */
  170.  
  171. struct Process        *FileRequesterProcess;
  172. struct MsgPort        *FileRequesterPort;
  173.  
  174.     /* Screen data. */
  175.  
  176. struct Screen        *PublicScreen,
  177.             *Screen;
  178.  
  179.     /* Menu data. */
  180.  
  181. APTR             VisualInfo;
  182. struct Menu        *Menu;
  183.  
  184. struct NewMenu MenuTemplate[] =
  185. {
  186.     { NM_TITLE, "Project",             0 ,    0,    0,    (APTR)0},
  187.     {  NM_ITEM, "Toggle chat",        "C",    0,    0,    (APTR)Alt_C},
  188.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  189.     {  NM_ITEM, "Hang up",            "H",    0,    0,    (APTR)Alt_H},
  190.     {  NM_ITEM, "Toggle duplex",        "E",    0,    0,    (APTR)Alt_E},
  191.     {  NM_ITEM, "Toggle 7 bits/8 bits",    "B",    0,    0,    (APTR)Alt_B},
  192.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  193.     {  NM_ITEM, "Start upload",        "U",    0,    0,    (APTR)PgUp},
  194.     {  NM_ITEM, "Start download",        "D",    0,    0,    (APTR)PgDn},
  195.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  196.     {  NM_ITEM, "Abort Hydra session",    ".",    0,    0,    (APTR)Esc},
  197.     {  NM_ITEM, NM_BARLABEL,         0 ,    0,    0,    (APTR)0},
  198.     {  NM_ITEM, "Exit HydraCom",        "Q",    0,    0,    (APTR)Alt_X},
  199.     { NM_END,   0,                 0 ,    0,    0,    (APTR)0}
  200. };
  201.  
  202.     /* Time data. */
  203.  
  204. LONG             GMT_Offset = UTC_OFFSET;
  205.  
  206.     /* Version ID. */
  207.  
  208. STRPTR VersionTag = "$VER: hydracom 1.0r6 (16.08.95)\r\n";
  209.  
  210.     /* CloseWindowSafely(struct Window *Window):
  211.      *
  212.      *    Close a window sharing its UserPort with other
  213.      *    windows.
  214.      */
  215.  
  216. STATIC VOID __regargs
  217. CloseWindowSafely(struct Window *Window)
  218. {
  219.     struct IntuiMessage    *IntuiMessage;
  220.     struct Node        *Successor;
  221.  
  222.     Forbid();
  223.  
  224.     if(Window -> UserPort)
  225.     {
  226.         IntuiMessage = (struct IntuiMessage *)Window -> UserPort -> mp_MsgList . lh_Head;
  227.  
  228.         while(Successor = IntuiMessage -> ExecMessage . mn_Node . ln_Succ)
  229.         {
  230.             if(IntuiMessage -> IDCMPWindow == Window)
  231.             {
  232.                 Remove((struct Node *)IntuiMessage);
  233.  
  234.                 ReplyMsg((struct Message *)IntuiMessage);
  235.             }
  236.  
  237.             IntuiMessage = (struct IntuiMessage *)Successor;
  238.         }
  239.  
  240.         Window -> UserPort = NULL;
  241.     }
  242.  
  243.     ModifyIDCMP(Window,NULL);
  244.  
  245.     Permit();
  246.  
  247.     CloseWindow(Window);
  248. }
  249.  
  250.     /* UpdateTime(struct timeval *Now):
  251.      *
  252.      *    Get the current time and/or update the current
  253.      *    time offset data.
  254.      */
  255.  
  256. STATIC VOID __regargs
  257. UpdateTime(struct timeval *Now)
  258. {
  259.     if(Now)
  260.         Now -> tv_secs = Now -> tv_micro = 0;
  261.  
  262.     if(TimePort = CreateMsgPort())
  263.     {
  264.         if(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest)))
  265.         {
  266.             if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  267.             {
  268.                 TimerBase = (struct Library *)TimeRequest -> tr_node . io_Device;
  269.  
  270.                 if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  271.                 {
  272.                     struct Locale *Locale;
  273.  
  274.                     if(Locale = OpenLocale(NULL))
  275.                     {
  276.                         GMT_Offset = 60 * Locale -> loc_GMTOffset + UTC_OFFSET;
  277.  
  278.                         CloseLocale(Locale);
  279.                     }
  280.  
  281.                     CloseLibrary(LocaleBase);
  282.  
  283.                     LocaleBase = NULL;
  284.                 }
  285.  
  286.                 if(Now)
  287.                     GetSysTime(Now);
  288.  
  289.                 TimerBase = NULL;
  290.  
  291.                 CloseDevice(TimeRequest);
  292.             }
  293.  
  294.             DeleteIORequest(TimeRequest);
  295.  
  296.             TimeRequest = NULL;
  297.         }
  298.  
  299.         DeleteMsgPort(TimePort);
  300.  
  301.         TimePort = NULL;
  302.     }
  303. }
  304.  
  305.     /* FileRequestEntry(VOID):
  306.      *
  307.      *    Asynchronous file request process entry.
  308.      */
  309.  
  310. STATIC VOID __saveds
  311. FileRequestEntry(VOID)
  312. {
  313.     struct FileRequester *FileRequester;
  314.  
  315.     if(FileRequester = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
  316.         ASLFR_TitleText,    "Select file(s) to upload",
  317.         ASLFR_InitialPattern,    "#?",
  318.         ASLFR_Flags1,        FRF_PRIVATEIDCMP | FRF_DOMULTISELECT | FRF_DOPATTERNS,
  319.     TAG_DONE))
  320.     {
  321.         if(FileRequesterPort = CreateMsgPort())
  322.         {
  323.             struct Message    *Message;
  324.             ULONG         Signals;
  325.             BOOL         Done = FALSE;
  326.  
  327.             FileRequesterProcess = (struct Process *)FindTask(NULL);
  328.  
  329.             Signal(ThisProcess,SIG_HANDSHAKE);
  330.  
  331.             do
  332.             {
  333.                 Signals = Wait((1L << FileRequesterPort -> mp_SigBit) | SIG_KILL);
  334.  
  335.                 if(Signals & (1L << FileRequesterPort -> mp_SigBit))
  336.                 {
  337.                     LONG MaxLen;
  338.  
  339.                     while(Message = GetMsg(FileRequesterPort))
  340.                     {
  341.                         MaxLen = (LONG)Message -> mn_Node . ln_Name;
  342.  
  343.                         if(AslRequestTags(FileRequester,
  344.                             ASLFR_Window,        LocalWindow,
  345.                             ASLFR_SleepWindow,    TRUE,
  346.                         TAG_DONE))
  347.                         {
  348.                             if(FileRequester -> fr_NumArgs > 0)
  349.                             {
  350.                                 UBYTE     LocalBuffer[256];
  351.                                 char    *String;
  352.                                 LONG     Len,Count,i;
  353.  
  354.                                 for(i = Len = 0 ; i < FileRequester -> fr_NumArgs ; i++)
  355.                                 {
  356.                                     if(FileRequester -> fr_ArgList[i] . wa_Lock)
  357.                                     {
  358.                                         if(NameFromLock(FileRequester -> fr_ArgList[i] . wa_Lock,LocalBuffer,256))
  359.                                             Len += strlen(LocalBuffer) + 1;
  360.                                     }
  361.                                     else
  362.                                         Len += strlen(FileRequester -> fr_Drawer) + 1;
  363.  
  364.                                     Len += strlen(FileRequester -> fr_ArgList[i] . wa_Name) + 1 + 2;
  365.                                 }
  366.  
  367.                                 Len++;
  368.  
  369.                                 if(String = AllocVec(Len,MEMF_ANY))
  370.                                 {
  371.                                     *String = 0;
  372.  
  373.                                     for(i = Count = 0 ; Count < MaxLen && i < FileRequester -> fr_NumArgs ; i++)
  374.                                     {
  375.                                         if(FileRequester -> fr_ArgList[i] . wa_Lock)
  376.                                         {
  377.                                             if(NameFromLock(FileRequester -> fr_ArgList[i] . wa_Lock,LocalBuffer,256))
  378.                                             {
  379.                                                 if(AddPart(LocalBuffer,FileRequester -> fr_ArgList[i] . wa_Name,256))
  380.                                                 {
  381.                                                     if(Count + strlen(LocalBuffer) + 2 < MaxLen)
  382.                                                     {
  383.                                                         strcat(String,"\"");
  384.                                                         strcat(String,LocalBuffer);
  385.                                                         strcat(String,"\"");
  386.  
  387.                                                         Count += strlen(LocalBuffer) + 2;
  388.                                                     }
  389.                                                     else
  390.                                                         break;
  391.                                                 }
  392.                                             }
  393.                                         }
  394.                                         else
  395.                                         {
  396.                                             strcpy(LocalBuffer,FileRequester -> fr_Drawer);
  397.  
  398.                                             if(AddPart(LocalBuffer,FileRequester -> fr_ArgList[i] . wa_Name,256))
  399.                                             {
  400.                                                 if(Count + strlen(LocalBuffer) + 2 < MaxLen)
  401.                                                 {
  402.                                                     strcat(String,"\"");
  403.                                                     strcat(String,LocalBuffer);
  404.                                                     strcat(String,"\"");
  405.  
  406.                                                     Count += strlen(LocalBuffer) + 2;
  407.                                                 }
  408.                                                 else
  409.                                                     break;
  410.                                             }
  411.                                         }
  412.  
  413.                                         if(i != FileRequester -> fr_NumArgs - 1)
  414.                                         {
  415.                                             strcat(String," ");
  416.                                             Count++;
  417.                                         }
  418.                                     }
  419.  
  420.                                     Message -> mn_Node . ln_Name = String;
  421.  
  422.                                     ReplyMsg(Message);
  423.  
  424.                                     Message = NULL;
  425.                                 }
  426.                             }
  427.                             else
  428.                             {
  429.                                 if(FileRequester -> fr_File[0])
  430.                                 {
  431.                                     LONG Len;
  432.  
  433.                                     Len = strlen(FileRequester -> fr_Drawer) + strlen(FileRequester -> fr_File) + 2 + 2;
  434.  
  435.                                     if(Len <= MaxLen)
  436.                                     {
  437.                                         char *String;
  438.  
  439.                                         if(String = AllocVec(Len,MEMF_ANY))
  440.                                         {
  441.                                             strcpy(String + 1,FileRequester -> fr_Drawer);
  442.  
  443.                                             if(AddPart(String + 1,FileRequester -> fr_File,Len))
  444.                                             {
  445.                                                 String[0] = '\"';
  446.                                                 strcat(String,"\"");
  447.  
  448.                                                 Message -> mn_Node . ln_Name = String;
  449.  
  450.                                                 ReplyMsg(Message);
  451.  
  452.                                                 Message = NULL;
  453.                                             }
  454.                                             else
  455.                                                 FreeVec(String);
  456.                                         }
  457.                                     }
  458.                                 }
  459.                             }
  460.                         }
  461.  
  462.                         if(Message)
  463.                         {
  464.                             Message -> mn_Node . ln_Name = NULL;
  465.  
  466.                             ReplyMsg(Message);
  467.                         }
  468.                     }
  469.                 }
  470.  
  471.                 if(Signals & SIG_KILL)
  472.                     Done = TRUE;
  473.             }
  474.             while(!Done);
  475.  
  476.             while(Message = GetMsg(FileRequesterPort))
  477.             {
  478.                 Message -> mn_Node . ln_Name = NULL;
  479.  
  480.                 ReplyMsg(Message);
  481.             }
  482.  
  483.             DeleteMsgPort(FileRequesterPort);
  484.         }
  485.  
  486.         FreeAslRequest(FileRequester);
  487.     }
  488.  
  489.     Forbid();
  490.  
  491.     FileRequesterProcess = NULL;
  492.  
  493.     Signal(ThisProcess,SIG_HANDSHAKE);
  494. }
  495.  
  496.     /* GetFiles(char *Buffer,int MaxLen):
  497.      *
  498.      *    Get a list of file names, asynchronously please.
  499.      */
  500.  
  501. char *
  502. GetFiles(char *Buffer,int MaxLen)
  503. {
  504.     struct MsgPort    *ReplyPort;
  505.     char        *Result = NULL;
  506.  
  507.     if(ReplyPort = CreateMsgPort())
  508.     {
  509.         struct Message *Message;
  510.  
  511.         if(Message = AllocVec(sizeof(struct Message),MEMF_ANY | MEMF_CLEAR))
  512.         {
  513.             Message -> mn_Length        = sizeof(struct Message);
  514.             Message -> mn_ReplyPort        = ReplyPort;
  515.             Message -> mn_Node . ln_Name    = (STRPTR)MaxLen;
  516.  
  517.             PutMsg(FileRequesterPort,Message);
  518.  
  519.             FOREVER
  520.             {
  521.                 if(SetSignal(0,(1L << ReplyPort -> mp_SigBit)) & (1L << ReplyPort -> mp_SigBit))
  522.                 {
  523.                     GetMsg(ReplyPort);
  524.  
  525.                     break;
  526.                 }
  527.  
  528.                 sys_idle();
  529.             }
  530.  
  531.             if(Message -> mn_Node . ln_Name)
  532.             {
  533.                 strcpy(Buffer,Message -> mn_Node . ln_Name);
  534.  
  535.                 FreeVec(Message -> mn_Node . ln_Name);
  536.  
  537.                 Result = Buffer;
  538.             }
  539.  
  540.             FreeVec(Message);
  541.         }
  542.  
  543.         DeleteMsgPort(ReplyPort);
  544.     }
  545.  
  546.     return(Result);
  547. }
  548.  
  549.     /* OpenConsole():
  550.      *
  551.      *    Open a console window.
  552.      */
  553.  
  554. STATIC BOOL __regargs
  555. OpenConsole(struct Screen *Screen,LONG Top,LONG Height,STRPTR Title,BOOL Resize,struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  556. {
  557.     struct Window *Window;
  558.  
  559.     if(Window = OpenWindowTags(NULL,
  560.         WA_Left,        0,
  561.         WA_Top,            Top,
  562.         WA_Width,        Screen -> Width,
  563.         WA_Height,        Height,
  564.         WA_Title,        Title,
  565.         WA_SimpleRefresh,    TRUE,
  566.         WA_DepthGadget,        TRUE,
  567.         WA_DragBar,        TRUE,
  568.         WA_SizeGadget,        Resize,
  569.         WA_SizeBRight,        TRUE,
  570.         WA_CustomScreen,    Screen,
  571.         WA_NewLookMenus,    TRUE,
  572.     TAG_DONE))
  573.     {
  574.         Window -> UserPort = WindowPort;
  575.  
  576.         SetMenuStrip(Window,Menu);
  577.  
  578.         if(ModifyIDCMP(Window,IDCMP_MENUPICK))
  579.         {
  580.             struct IOStdReq *ConsoleRequest;
  581.  
  582.             if(Window -> RPort -> Font -> tf_Flags & FPF_PROPORTIONAL)
  583.                 SetFont(Window -> RPort,GfxBase -> DefaultFont);
  584.  
  585.             if(ConsoleRequest = (struct IOStdReq *)CreateIORequest(ConsoleWritePort,sizeof(struct IOStdReq)))
  586.             {
  587.                 ConsoleRequest -> io_Data = Window;
  588.  
  589.                 if(!OpenDevice("console.device",CONU_CHARMAP,ConsoleRequest,CONFLAG_DEFAULT))
  590.                 {
  591.                     WindowLimits(Window,Window -> BorderLeft + 10 * Window -> RPort -> Font -> tf_XSize * 10 + Window -> BorderRight,Window -> BorderTop + 2 * Window -> RPort -> Font -> tf_YSize + Window -> BorderBottom,Screen -> Width,Screen -> Height);
  592.  
  593.                         /* Turn off the cursor. */
  594.  
  595.                     ConPrintf(ConsoleRequest,"\033[0 p");
  596.  
  597.                     *WindowPtr    = Window;
  598.                     *ConsolePtr    = ConsoleRequest;
  599.  
  600.                     return(TRUE);
  601.                 }
  602.  
  603.                 DeleteIORequest(ConsoleRequest);
  604.             }
  605.         }
  606.  
  607.         ClearMenuStrip(Window);
  608.  
  609.         CloseWindowSafely(Window);
  610.     }
  611.  
  612.     return(FALSE);
  613. }
  614.  
  615.     /* CloseConsole():
  616.      *
  617.      *    Close a console window.
  618.      */
  619.  
  620. STATIC VOID __regargs
  621. CloseConsole(struct Window **WindowPtr,struct IOStdReq **ConsolePtr)
  622. {
  623.     if(*ConsolePtr)
  624.     {
  625.         CloseDevice(*ConsolePtr);
  626.  
  627.         DeleteIORequest(*ConsolePtr);
  628.  
  629.         *ConsolePtr = NULL;
  630.     }
  631.  
  632.     if(*WindowPtr)
  633.     {
  634.         ClearMenuStrip(*WindowPtr);
  635.  
  636.         CloseWindowSafely(*WindowPtr);
  637.  
  638.         *WindowPtr = NULL;
  639.     }
  640. }
  641.  
  642.     /* CloneSerialBuffer():
  643.      *
  644.      *    Clone a SerialBuffer structure.
  645.      */
  646.  
  647. STATIC struct SerialBuffer * __regargs
  648. CloneSerialBuffer(struct SerialBuffer *Source,struct MsgPort *MsgPort)
  649. {
  650.     struct SerialBuffer *Buffer;
  651.  
  652.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Source -> SerialSize,MEMF_ANY | MEMF_PUBLIC))
  653.     {
  654.         Buffer -> SerialBuffer    = Buffer -> SerialIndex = (UBYTE *)(Buffer + 1);
  655.         Buffer -> SerialFilled    = 0;
  656.         Buffer -> SerialTop    = Buffer -> SerialBuffer + Source -> SerialSize;
  657.         Buffer -> SerialSize    = Source -> SerialSize;
  658.         Buffer -> IsClone    = TRUE;
  659.         Buffer -> IsBusy    = FALSE;
  660.  
  661.         if(Buffer -> SerialRequest = (struct IOExtSer *)AllocVec(sizeof(struct IOExtSer),MEMF_ANY | MEMF_PUBLIC))
  662.         {
  663.             CopyMem(Source -> SerialRequest,Buffer -> SerialRequest,sizeof(struct IOExtSer));
  664.  
  665.             Buffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = MsgPort;
  666.  
  667.             return(Buffer);
  668.         }
  669.         else
  670.             cprint("Could not create serial request\n");
  671.  
  672.         FreeVec(Buffer);
  673.     }
  674.     else
  675.         cprint("Could not create serial buffer\n");
  676.  
  677.     return(NULL);
  678. }
  679.  
  680.     /* DeleteSerialBuffer():
  681.      *
  682.      *    Delete a SerialBuffer structure.
  683.      */
  684.  
  685. STATIC VOID __regargs
  686. DeleteSerialBuffer(struct SerialBuffer *Buffer)
  687. {
  688.     if(Buffer)
  689.     {
  690.         if(Buffer -> IsBusy)
  691.         {
  692.             if(!CheckIO(Buffer -> SerialRequest))
  693.                 AbortIO(Buffer -> SerialRequest);
  694.  
  695.             WaitIO(Buffer -> SerialRequest);
  696.         }
  697.  
  698.         if(Buffer -> IsClone)
  699.             FreeVec(Buffer -> SerialRequest);
  700.         else
  701.         {
  702.             CloseDevice(Buffer -> SerialRequest);
  703.  
  704.             DeleteIORequest(Buffer -> SerialRequest);
  705.         }
  706.  
  707.         FreeVec(Buffer);
  708.     }
  709. }
  710.  
  711.     /* CreateSerialBuffer():
  712.      *
  713.      *    Create a serial buffer structure.
  714.      */
  715.  
  716. STATIC struct SerialBuffer * __regargs
  717. CreateSerialBuffer(STRPTR Device,LONG Unit,LONG Size,struct MsgPort *MsgPort)
  718. {
  719.     struct SerialBuffer *Buffer;
  720.  
  721.     if(Buffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + Size,MEMF_ANY | MEMF_PUBLIC))
  722.     {
  723.         Buffer -> SerialBuffer    = Buffer -> SerialIndex = (UBYTE *)(Buffer + 1);
  724.         Buffer -> SerialFilled    = 0;
  725.         Buffer -> SerialTop    = Buffer -> SerialBuffer + Size;
  726.         Buffer -> SerialSize    = Size;
  727.         Buffer -> IsClone    = FALSE;
  728.         Buffer -> IsBusy    = FALSE;
  729.  
  730.         if(Buffer -> SerialRequest = (struct IOExtSer *)CreateIORequest(MsgPort,sizeof(struct IOExtSer)))
  731.         {
  732.             Buffer -> SerialRequest -> io_SerFlags = SERF_SHARED;
  733.  
  734.             if(!OpenDevice(Device,Unit,Buffer -> SerialRequest,NULL))
  735.                 return(Buffer);
  736.             else
  737.             {
  738.                 cprint("Could not open \"%s\", unit %d\n",Device,Unit);
  739.  
  740.                 DeleteIORequest(Buffer -> SerialRequest);
  741.             }
  742.         }
  743.         else
  744.             cprint("Could not create serial request\n");
  745.  
  746.         FreeVec(Buffer);
  747.     }
  748.     else
  749.         cprint("Could not create serial buffer\n");
  750.  
  751.     return(NULL);
  752. }
  753.  
  754.     /* OpenAll():
  755.      *
  756.      *    Allocate all the resources required.
  757.      */
  758.  
  759. STATIC BOOL
  760. OpenAll(STRPTR Device,LONG Unit)
  761. {
  762.     LONG Top,Lines,BorderSize,FontSize,ExtraLines,RemainingLines,TotalHeight;
  763.     UWORD Pens = (UWORD)~0;
  764.  
  765.     ThisProcess = (struct Process *)FindTask(NULL);
  766.  
  767.     if(pri != 1000)
  768.     {
  769.         if(pri < -128)
  770.             pri = 128;
  771.         else
  772.         {
  773.             if(pri > 127)
  774.                 pri = 127;
  775.         }
  776.  
  777.         OldPri = SetTaskPri(ThisProcess,pri);
  778.     }
  779.  
  780.     if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37)))
  781.     {
  782.         cprint("Could not open intuition.library v37\n");
  783.  
  784.         return(FALSE);
  785.     }
  786.  
  787.     if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",37)))
  788.     {
  789.         cprint("Could not open graphics.library v37\n");
  790.  
  791.         return(FALSE);
  792.     }
  793.  
  794.     if(!(GadToolsBase = OpenLibrary("gadtools.library",37)))
  795.     {
  796.         cprint("Could not open gadtools.library v37\n");
  797.  
  798.         return(FALSE);
  799.     }
  800.  
  801.     if(!(UtilityBase = OpenLibrary("utility.library",37)))
  802.     {
  803.         cprint("Could not open utility.library v37\n");
  804.  
  805.         return(FALSE);
  806.     }
  807.  
  808.     if(!(AslBase = OpenLibrary("asl.library",37)))
  809.     {
  810.         cprint("Could not open asl.library v37\n");
  811.  
  812.         return(FALSE);
  813.     }
  814.  
  815.     if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  816.     {
  817.         struct Locale *Locale;
  818.  
  819.         if(Locale = OpenLocale(NULL))
  820.         {
  821.             GMT_Offset = 60 * Locale -> loc_GMTOffset + UTC_OFFSET;
  822.  
  823.             CloseLocale(Locale);
  824.         }
  825.  
  826.         CloseLibrary(LocaleBase);
  827.     }
  828.  
  829.     Forbid();
  830.  
  831.     if(CreateNewProcTags(
  832.         NP_Name,    "HydraCom Filerequester Process",
  833.         NP_WindowPtr,    -1,
  834.         NP_Entry,    FileRequestEntry,
  835.     TAG_DONE))
  836.     {
  837.         ClrSignal(SIG_HANDSHAKE);
  838.  
  839.         Wait(SIG_HANDSHAKE);
  840.     }
  841.  
  842.     Permit();
  843.  
  844.     if(!FileRequesterProcess)
  845.     {
  846.         cprint("Could not create file requester process\n");
  847.  
  848.         return(FALSE);
  849.     }
  850.  
  851.     if(!(TimePort = CreateMsgPort()))
  852.     {
  853.         cprint("Could not create timer port\n");
  854.  
  855.         return(FALSE);
  856.     }
  857.  
  858.     if(!(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest))))
  859.     {
  860.         cprint("Could not create timer request\n");
  861.  
  862.         return(FALSE);
  863.     }
  864.  
  865.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL))
  866.     {
  867.         cprint("Could not open timer\n");
  868.  
  869.         return(FALSE);
  870.     }
  871.  
  872.     TimerBase = (struct Library *)TimeRequest -> tr_node . io_Device;
  873.  
  874.     if(!(Anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath) + 512,MEMF_ANY | MEMF_CLEAR)))
  875.     {
  876.         cprint("Could not allocate pattern matching buffe\n");
  877.  
  878.         return(FALSE);
  879.     }
  880.  
  881.     Anchor -> ap_Strlen = 512;
  882.  
  883.     if(!(ReadPort = CreateMsgPort()))
  884.     {
  885.         cprint("Could not create serial read port\n");
  886.  
  887.         return(FALSE);
  888.     }
  889.  
  890.     if(!(WritePort = CreateMsgPort()))
  891.     {
  892.         cprint("Could not create serial write port\n");
  893.  
  894.         return(FALSE);
  895.     }
  896.  
  897.     Forbid();
  898.  
  899.     if(RendezvousSemaphore = (struct RendezvousSemaphore *)FindSemaphore(Device))
  900.     {
  901.         ObtainSemaphore(RendezvousSemaphore);
  902.  
  903.         if(!(RendezvousData = (*RendezvousSemaphore -> rs_Login)(ReadPort,WritePort,NULL)))
  904.         {
  905.             Permit();
  906.  
  907.             ReleaseSemaphore(RendezvousSemaphore);
  908.  
  909.             RendezvousSemaphore = NULL;
  910.  
  911.             cprint("Could not link to `term' port \"%s\"\n",Device);
  912.  
  913.             return(FALSE);
  914.         }
  915.     }
  916.  
  917.     Permit();
  918.  
  919.     if(!(ConsoleReadPort = CreateMsgPort()))
  920.     {
  921.         cprint("Could not create console read port\n");
  922.  
  923.         return(FALSE);
  924.     }
  925.  
  926.     if(!(ConsoleWritePort = CreateMsgPort()))
  927.     {
  928.         cprint("Could not create console write port\n");
  929.  
  930.         return(FALSE);
  931.     }
  932.  
  933.     if(!(ConsoleReadRequest = (struct IOStdReq *)AllocVec(sizeof(struct IOStdReq),MEMF_ANY | MEMF_PUBLIC | MEMF_CLEAR)))
  934.     {
  935.         cprint("Could not create console read request\n");
  936.  
  937.         return(FALSE);
  938.     }
  939.  
  940.     if(!RendezvousData)
  941.     {
  942.         if(!(ReadBuffer = CreateSerialBuffer(Device,Unit,BUFFER_SIZE,ReadPort)))
  943.             return(FALSE);
  944.     }
  945.     else
  946.     {
  947.         if(ReadBuffer = (struct SerialBuffer *)AllocVec(sizeof(struct SerialBuffer) + BUFFER_SIZE,MEMF_ANY | MEMF_PUBLIC))
  948.         {
  949.             ReadBuffer -> SerialBuffer    = ReadBuffer -> SerialIndex = (UBYTE *)(ReadBuffer + 1);
  950.             ReadBuffer -> SerialFilled    = 0;
  951.             ReadBuffer -> SerialTop        = ReadBuffer -> SerialBuffer + BUFFER_SIZE;
  952.             ReadBuffer -> SerialSize    = BUFFER_SIZE;
  953.             ReadBuffer -> IsClone        = TRUE;
  954.             ReadBuffer -> IsBusy        = FALSE;
  955.             ReadBuffer -> SerialRequest    = &RendezvousData -> rd_ReadRequest;
  956.         }
  957.         else
  958.         {
  959.             cprint("Could not create serial ReadBuffer\n");
  960.  
  961.             return(FALSE);
  962.         }
  963.     }
  964.  
  965.     if(!(ThisBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  966.         return(FALSE);
  967.  
  968.     if(!(NextBuffer = CloneSerialBuffer(ReadBuffer,WritePort)))
  969.         return(FALSE);
  970.  
  971.     if(!(PublicScreen = LockPubScreen(NULL)))
  972.     {
  973.         cprint("Could not find default public screen\n");
  974.  
  975.         return(FALSE);
  976.     }
  977.  
  978.     if(RendezvousData)
  979.     {
  980.         if(!(Screen = RendezvousData -> rd_Screen))
  981.             Screen = PublicScreen;
  982.     }
  983.     else
  984.     {
  985.         if(!(Screen = OpenScreenTags(NULL,
  986.             SA_DisplayID,    GetVPModeID(&PublicScreen -> ViewPort),
  987.             SA_Overscan,    OSCAN_TEXT,
  988.             SA_Depth,    2,
  989.             SA_Title,    PRGNAME " " VERSION " " HC_OS " Amiga rev 6, ported by Olaf `Olsen' Barthel",
  990.             SA_Behind,    TRUE,
  991.             SA_SysFont,    1,
  992.             SA_Pens,    &Pens,
  993.             SA_Interleaved,    TRUE,
  994.         TAG_DONE)))
  995.         {
  996.             cprint("Could not open screen\n");
  997.  
  998.             return(FALSE);
  999.         }
  1000.     }
  1001.  
  1002.     if(!(VisualInfo = GetVisualInfo(Screen,TAG_DONE)))
  1003.     {
  1004.         cprint("Could not obtain screen visual info\n");
  1005.  
  1006.         return(FALSE);
  1007.     }
  1008.  
  1009.     if(!(Menu = CreateMenus(MenuTemplate,TAG_DONE)))
  1010.     {
  1011.         cprint("Could not create menus\n");
  1012.  
  1013.         return(FALSE);
  1014.     }
  1015.  
  1016.     if(!LayoutMenus(Menu,VisualInfo,
  1017.         GTMN_TextAttr,        Screen -> Font,
  1018.         GTMN_NewLookMenus,    TRUE,
  1019.     TAG_DONE))
  1020.     {
  1021.         cprint("Could not layout menus\n");
  1022.  
  1023.         return(FALSE);
  1024.     }
  1025.  
  1026.     Top        = Screen -> BarHeight + 1;
  1027.     BorderSize    = Screen -> WBorTop + Screen -> Font -> ta_YSize + 1 + Screen -> WBorBottom;
  1028.     FontSize    = GfxBase -> DefaultFont -> tf_YSize;
  1029.     TotalHeight    = Screen -> Height - Top;
  1030.     Lines        = (TotalHeight - 3 - 4 * BorderSize) / FontSize;
  1031.     ExtraLines    = Lines > MIN_LINES ? (Lines - MIN_LINES) / 3 : 0;
  1032.     RemainingLines    = Lines > MIN_LINES + ExtraLines * 3 ? Lines - (MIN_LINES + ExtraLines * 3) : 0;
  1033.  
  1034.     if(Lines < MIN_LINES)
  1035.     {
  1036.         cprint("Screen size too small (need at least %d text lines, can get only %d)\n",MIN_LINES,Lines);
  1037.  
  1038.         return(FALSE);
  1039.     }
  1040.  
  1041.     if(!(WindowPort = CreateMsgPort()))
  1042.     {
  1043.         cprint("Could not create window port\n");
  1044.  
  1045.         return(FALSE);
  1046.     }
  1047.  
  1048.     if(!OpenConsole(Screen,Top,BorderSize + (6 + ExtraLines) * FontSize,"Log",TRUE,&LogWindow,&LogRequest))
  1049.     {
  1050.         cprint("Could not open console window #1\n");
  1051.  
  1052.         return(FALSE);
  1053.     }
  1054.  
  1055.     TotalHeight    -= LogWindow -> Height + 1;
  1056.     Top        += LogWindow -> Height + 1;
  1057.  
  1058.     if(!OpenConsole(Screen,Top,BorderSize + 2 * FontSize,"File",FALSE,&FileWindow,&FileRequest))
  1059.     {
  1060.         cprint("Could not open console window #2\n");
  1061.  
  1062.         return(FALSE);
  1063.     }
  1064.  
  1065.     ConPrintf(FileRequest,"\033[?7l");
  1066.  
  1067.     TotalHeight    -= FileWindow -> Height + 1;
  1068.     Top        += FileWindow -> Height + 1;
  1069.  
  1070.     if(!OpenConsole(Screen,Top,BorderSize + (8 + RemainingLines) * FontSize,"Remote",TRUE,&RemoteWindow,&RemoteRequest))
  1071.     {
  1072.         cprint("Could not open console window #3\n");
  1073.  
  1074.         return(FALSE);
  1075.     }
  1076.  
  1077.     TotalHeight    -= RemoteWindow -> Height + 1;
  1078.     Top        += RemoteWindow -> Height + 1;
  1079.  
  1080.     if(!OpenConsole(Screen,Top,TotalHeight,"Local (Press [Amiga+C] to start/end chat mode, [Esc] to abort Hydra session)",TRUE,&LocalWindow,&LocalRequest))
  1081.     {
  1082.         cprint("Could not open console window #4\n");
  1083.  
  1084.         return(FALSE);
  1085.     }
  1086.  
  1087.     CopyMem(LocalRequest,ConsoleReadRequest,sizeof(struct IOStdReq));
  1088.  
  1089.     ConsoleReadRequest -> io_Message . mn_ReplyPort = ConsoleReadPort;
  1090.  
  1091.         /* Turn the cursors back on. */
  1092.  
  1093.     ConPrintf(LocalRequest,"\33[ p");
  1094.     ConPrintf(RemoteRequest,"\33[ p");
  1095.  
  1096.     ConsoleReadRequest -> io_Command    = CMD_READ;
  1097.     ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1098.     ConsoleReadRequest -> io_Length        = 1;
  1099.  
  1100.     ClrSignal(SIG_CONREAD);
  1101.     SendIO(ConsoleReadRequest);
  1102.  
  1103.     OldPtr = ThisProcess -> pr_WindowPtr;
  1104.  
  1105.     ThisProcess -> pr_WindowPtr = (APTR)LocalWindow;
  1106.  
  1107.     ScreenToFront(Screen);
  1108.  
  1109.     ActivateWindow(LocalWindow);
  1110.  
  1111.     UnlockPubScreen(NULL,PublicScreen);
  1112.  
  1113.     PublicScreen = NULL;
  1114.  
  1115.     if(!RendezvousData)
  1116.         com_flow(flowflags);
  1117.  
  1118.     return(TRUE);
  1119. }
  1120.  
  1121.     /* CloseAll():
  1122.      *
  1123.      *    Close all the resources.
  1124.      */
  1125.  
  1126. STATIC VOID
  1127. CloseAll(VOID)
  1128. {
  1129.     if(FileRequesterProcess)
  1130.     {
  1131.         Forbid();
  1132.  
  1133.         ClrSignal(SIG_HANDSHAKE);
  1134.  
  1135.         Signal(FileRequesterProcess,SIG_KILL);
  1136.  
  1137.         Wait(SIG_HANDSHAKE);
  1138.  
  1139.         Permit();
  1140.     }
  1141.  
  1142.     if(LocalWindow)
  1143.         ClearMenuStrip(LocalWindow);
  1144.  
  1145.     if(Menu)
  1146.         FreeMenus(Menu);
  1147.  
  1148.     if(VisualInfo)
  1149.         FreeVisualInfo(VisualInfo);
  1150.  
  1151.     if(AnchorUsed)
  1152.         MatchEnd(Anchor);
  1153.  
  1154.     if(Anchor)
  1155.         FreeVec(Anchor);
  1156.  
  1157.     if(ThisProcess)
  1158.         ThisProcess -> pr_WindowPtr = OldPtr;
  1159.  
  1160.     if(ConsoleReadRequest)
  1161.     {
  1162.         if(ConsoleReadRequest -> io_Device)
  1163.         {
  1164.             if(!CheckIO(ConsoleReadRequest))
  1165.                 AbortIO(ConsoleReadRequest);
  1166.  
  1167.             WaitIO(ConsoleReadRequest);
  1168.         }
  1169.  
  1170.         FreeVec(ConsoleReadRequest);
  1171.     }
  1172.  
  1173.     CloseConsole(&LocalWindow,&LocalRequest);
  1174.     CloseConsole(&RemoteWindow,&RemoteRequest);
  1175.     CloseConsole(&FileWindow,&FileRequest);
  1176.     CloseConsole(&LogWindow,&LogRequest);
  1177.  
  1178.     if(WindowPort)
  1179.         DeleteMsgPort(WindowPort);
  1180.  
  1181.     if(!RendezvousData && Screen)
  1182.         CloseScreen(Screen);
  1183.  
  1184.     if(PublicScreen)
  1185.         UnlockPubScreen(NULL,PublicScreen);
  1186.  
  1187.     DeleteSerialBuffer(NextBuffer);
  1188.     DeleteSerialBuffer(ThisBuffer);
  1189.  
  1190.     if(RendezvousData)
  1191.     {
  1192.         if(ReadBuffer -> IsBusy)
  1193.         {
  1194.             if(!CheckIO(ReadBuffer -> SerialRequest))
  1195.                 AbortIO(ReadBuffer -> SerialRequest);
  1196.  
  1197.             WaitIO(ReadBuffer -> SerialRequest);
  1198.         }
  1199.  
  1200.         FreeVec(ReadBuffer);
  1201.     }
  1202.     else
  1203.         DeleteSerialBuffer(ReadBuffer);
  1204.  
  1205.     if(ConsoleWritePort)
  1206.         DeleteMsgPort(ConsoleWritePort);
  1207.  
  1208.     if(ConsoleReadPort)
  1209.         DeleteMsgPort(ConsoleReadPort);
  1210.  
  1211.     if(WritePort)
  1212.         DeleteMsgPort(WritePort);
  1213.  
  1214.     if(ReadPort)
  1215.         DeleteMsgPort(ReadPort);
  1216.  
  1217.     if(TimeRequest)
  1218.     {
  1219.         if(TimeRequest -> tr_node . io_Device)
  1220.             CloseDevice(TimeRequest);
  1221.  
  1222.         DeleteIORequest(TimeRequest);
  1223.     }
  1224.  
  1225.     if(TimePort)
  1226.         DeleteMsgPort(TimePort);
  1227.  
  1228.     if(UtilityBase)
  1229.         CloseLibrary(UtilityBase);
  1230.  
  1231.     if(AslBase)
  1232.         CloseLibrary(AslBase);
  1233.  
  1234.     if(GadToolsBase)
  1235.         CloseLibrary(GadToolsBase);
  1236.  
  1237.     if(GfxBase)
  1238.         CloseLibrary(GfxBase);
  1239.  
  1240.     if(IntuitionBase)
  1241.         CloseLibrary(IntuitionBase);
  1242.  
  1243.     if(RendezvousData)
  1244.     {
  1245.         (*RendezvousSemaphore -> rs_Logoff)(RendezvousData);
  1246.  
  1247.         RendezvousData = NULL;
  1248.     }
  1249.  
  1250.     if(RendezvousSemaphore)
  1251.     {
  1252.         ReleaseSemaphore(RendezvousSemaphore);
  1253.  
  1254.         RendezvousSemaphore = NULL;
  1255.     }
  1256.  
  1257.     if(pri != 1000)
  1258.         OldPri = SetTaskPri(ThisProcess,OldPri);
  1259. }
  1260.  
  1261.     /* ConPutc():
  1262.      *
  1263.      *    Output a single character.
  1264.      */
  1265.  
  1266. VOID __stdargs
  1267. ConPutc(struct IOStdReq *Request,UBYTE Char)
  1268. {
  1269.     Request -> io_Command    = CMD_WRITE;
  1270.     Request -> io_Data    = &Char;
  1271.     Request -> io_Length    = 1;
  1272.  
  1273.     DoIO(Request);
  1274. }
  1275.  
  1276.     /* ConPuts():
  1277.      *
  1278.      *    Output a string.
  1279.      */
  1280.  
  1281. VOID
  1282. ConPuts(struct IOStdReq *Request,STRPTR String)
  1283. {
  1284.     Request -> io_Command    = CMD_WRITE;
  1285.     Request -> io_Data    = String;
  1286.     Request -> io_Length    = strlen(String);
  1287.  
  1288.     DoIO(Request);
  1289. }
  1290.  
  1291.     /* ConPrintf():
  1292.      *
  1293.      *    Formatted console output.
  1294.      */
  1295.  
  1296. VOID __stdargs
  1297. ConPrintf(struct IOStdReq *Request,STRPTR Format,...)
  1298. {
  1299.     STATIC UBYTE Buffer[512];
  1300.  
  1301.     va_list    VarArgs;
  1302.     LONG    Len;
  1303.  
  1304.     va_start(VarArgs,Format);
  1305.     vsprintf(Buffer,Format,VarArgs);
  1306.     va_end(VarArgs);
  1307.  
  1308.     Len = strlen(Buffer);
  1309.  
  1310.     if(Buffer[0] != '\033' && Request == FileRequest)
  1311.     {
  1312.         struct ConUnit *Unit = (struct ConUnit *)Request -> io_Unit;
  1313.  
  1314.         if(Unit -> cu_XCCP + Len > Unit -> cu_XMax)
  1315.         {
  1316.             if((Len = Unit -> cu_XMax - Unit -> cu_XCCP) < 1)
  1317.                 return;
  1318.         }
  1319.     }
  1320.  
  1321.     Request -> io_Command    = CMD_WRITE;
  1322.     Request -> io_Data    = Buffer;
  1323.     Request -> io_Length    = Len;
  1324.  
  1325.     DoIO(Request);
  1326. }
  1327.  
  1328.     /* ConMove():
  1329.      *
  1330.      *    Move the cursor to a new position.
  1331.      */
  1332.  
  1333. VOID
  1334. ConMove(struct IOStdReq *Request,LONG x,LONG y)
  1335. {
  1336.     ConPrintf(Request,"\33[%ld;%ldH",y,x);
  1337. }
  1338.  
  1339.     /* ConClear():
  1340.      *
  1341.      *    Clear the console window.
  1342.      */
  1343.  
  1344. VOID
  1345. ConClear(struct IOStdReq *Request)
  1346. {
  1347.     struct ConUnit *ConUnit = (struct ConUnit *)Request -> io_Device;
  1348.     LONG x,y;
  1349.  
  1350.     x = ConUnit -> cu_XCCP;
  1351.     y = ConUnit -> cu_YCCP;
  1352.  
  1353.     ConPrintf(Request,"\033[2J\33[%ld;%ldH",y,x);
  1354. }
  1355.  
  1356.     /* ConGetKey():
  1357.      *
  1358.      *    Read a character from a console window.
  1359.      */
  1360.  
  1361. int
  1362. ConGetKey()
  1363. {
  1364.     if(ConsoleReady)
  1365.     {
  1366.         int Result = ConsoleChar;
  1367.  
  1368.         ConsoleReady = FALSE;
  1369.  
  1370.         ConsoleReadRequest -> io_Command    = CMD_READ;
  1371.         ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1372.         ConsoleReadRequest -> io_Length        = 1;
  1373.  
  1374.         ClrSignal(SIG_CONREAD);
  1375.         SendIO(ConsoleReadRequest);
  1376.  
  1377.         return(Result);
  1378.     }
  1379.     else
  1380.     {
  1381.         int Result = 0;
  1382.  
  1383.         if(WindowReady)
  1384.         {
  1385.             struct IntuiMessage *IntuiMessage;
  1386.             ULONG MsgClass;
  1387.             UWORD MsgCode;
  1388.  
  1389.             while(IntuiMessage = (struct IntuiMessage *)GetMsg(LocalWindow -> UserPort))
  1390.             {
  1391.                 MsgClass    = IntuiMessage -> Class;
  1392.                 MsgCode        = IntuiMessage -> Code;
  1393.  
  1394.                 ReplyMsg(IntuiMessage);
  1395.  
  1396.                 if(MsgClass == IDCMP_MENUPICK)
  1397.                 {
  1398.                     struct MenuItem *Item;
  1399.  
  1400.                     while(MsgCode != MENUNULL)
  1401.                     {
  1402.                         if(Item = ItemAddress(Menu,MsgCode))
  1403.                         {
  1404.                             if(MENU_USERDATA(Item))
  1405.                             {
  1406.                                 if(!Result)
  1407.                                     Result = (int)MENU_USERDATA(Item);
  1408.                             }
  1409.  
  1410.                             MsgCode = Item -> NextSelect;
  1411.                         }
  1412.                         else
  1413.                             break;
  1414.                     }
  1415.                 }
  1416.             }
  1417.  
  1418.             WindowReady = FALSE;
  1419.         }
  1420.  
  1421.         return(Result);
  1422.     }
  1423. }
  1424.  
  1425.     /* ConScanKey():
  1426.      *
  1427.      *    Check for a keyboard event.
  1428.      */
  1429.  
  1430. int
  1431. ConScanKey()
  1432. {
  1433.     if(ConsoleReady || WindowReady)
  1434.         return(1);
  1435.     else
  1436.     {
  1437.         int Result = 0;
  1438.  
  1439.         if(CheckSignal(SIG_WINDOW))
  1440.         {
  1441.             WindowReady = TRUE;
  1442.  
  1443.             Result = 1;
  1444.         }
  1445.  
  1446.         if(CheckIO(ConsoleReadRequest))
  1447.         {
  1448.             if(!WaitIO(ConsoleReadRequest))
  1449.             {
  1450.                 ConsoleReady = TRUE;
  1451.  
  1452.                 return(1);
  1453.             }
  1454.             else
  1455.             {
  1456.                 ConsoleReadRequest -> io_Command    = CMD_READ;
  1457.                 ConsoleReadRequest -> io_Data        = &ConsoleChar;
  1458.                 ConsoleReadRequest -> io_Length        = 1;
  1459.  
  1460.                 ClrSignal(SIG_CONREAD);
  1461.                 SendIO(ConsoleReadRequest);
  1462.             }
  1463.         }
  1464.  
  1465.         return(Result);
  1466.     }
  1467.  
  1468.     return(0);
  1469. }
  1470.  
  1471.     /* dtr_out(byte flag):
  1472.      *
  1473.      *    If flag == 0 -> drop DTR signal, else set it.
  1474.      */
  1475.  
  1476. VOID
  1477. dtr_out(byte flag)
  1478. {
  1479.     if(!flag && !RendezvousData)
  1480.     {
  1481.         if(ThisBuffer -> IsBusy)
  1482.         {
  1483.             WaitIO(ThisBuffer -> SerialRequest);
  1484.  
  1485.             ThisBuffer -> IsBusy        = FALSE;
  1486.             ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1487.         }
  1488.  
  1489.         if(ReadBuffer -> IsBusy)
  1490.         {
  1491.             if(!CheckIO(ReadBuffer -> SerialRequest))
  1492.                 AbortIO(ReadBuffer -> SerialRequest);
  1493.  
  1494.             WaitIO(ReadBuffer -> SerialRequest);
  1495.  
  1496.             ReadBuffer -> IsBusy        = FALSE;
  1497.             ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1498.             ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1499.  
  1500.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1501.  
  1502.             DoIO(ReadBuffer -> SerialRequest);
  1503.  
  1504.             if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1505.             {
  1506.                 LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1507.  
  1508.                 if(Size > 0)
  1509.                 {
  1510.                     if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1511.                         Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1512.  
  1513.                     ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1514.                     ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1515.                     ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1516.  
  1517.                     DoIO(ReadBuffer -> SerialRequest);
  1518.  
  1519.                     ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1520.                 }
  1521.             }
  1522.         }
  1523.  
  1524.         CloseDevice(ReadBuffer -> SerialRequest);
  1525.  
  1526.         TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1527.         TimeRequest -> tr_time . tv_secs    = 1;
  1528.         TimeRequest -> tr_time . tv_micro    = 0;
  1529.  
  1530.         DoIO(TimeRequest);
  1531.  
  1532.         if(OpenDevice(device,port,ReadBuffer -> SerialRequest,NULL))
  1533.         {
  1534.             CloseAll();
  1535.  
  1536.             exit(10);
  1537.         }
  1538.         else
  1539.         {
  1540.             ReadBuffer -> SerialRequest -> io_Baud        = ThisBuffer -> SerialRequest -> io_Baud;
  1541.             ReadBuffer -> SerialRequest -> io_ReadLen    = ThisBuffer -> SerialRequest -> io_ReadLen;
  1542.             ReadBuffer -> SerialRequest -> io_WriteLen    = ThisBuffer -> SerialRequest -> io_WriteLen;
  1543.             ReadBuffer -> SerialRequest -> io_SerFlags    = ThisBuffer -> SerialRequest -> io_SerFlags;
  1544.  
  1545.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1546.  
  1547.             DoIO(ReadBuffer -> SerialRequest);
  1548.  
  1549.             CopyMem(ReadBuffer -> SerialRequest,ThisBuffer -> SerialRequest,sizeof(struct IOExtSer));
  1550.  
  1551.             ThisBuffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
  1552.  
  1553.             CopyMem(ReadBuffer -> SerialRequest,NextBuffer -> SerialRequest,sizeof(struct IOExtSer));
  1554.  
  1555.             NextBuffer -> SerialRequest -> IOSer . io_Message . mn_ReplyPort = WritePort;
  1556.         }
  1557.     }
  1558. }
  1559.  
  1560.     /* com_flow(byte flags):
  1561.      *
  1562.      *    The bit mask `flags' determines the style(s) of
  1563.      *    handshaking:
  1564.      *
  1565.      *    if (flags & 9) -> enable xON/xOFF software handshaking,
  1566.      *    if (flags & 2) -> enable RTS/CTS hardware handshaking
  1567.      */
  1568.  
  1569. VOID
  1570. com_flow(byte flags)
  1571. {
  1572.     if(ThisBuffer -> IsBusy)
  1573.     {
  1574.         WaitIO(ThisBuffer -> SerialRequest);
  1575.  
  1576.         ThisBuffer -> IsBusy        = FALSE;
  1577.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1578.     }
  1579.  
  1580.     if(ReadBuffer -> IsBusy)
  1581.     {
  1582.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1583.             AbortIO(ReadBuffer -> SerialRequest);
  1584.  
  1585.         WaitIO(ReadBuffer -> SerialRequest);
  1586.  
  1587.         ReadBuffer -> IsBusy        = FALSE;
  1588.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1589.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1590.  
  1591.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1592.  
  1593.         DoIO(ReadBuffer -> SerialRequest);
  1594.  
  1595.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1596.         {
  1597.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1598.  
  1599.             if(Size > 0)
  1600.             {
  1601.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1602.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1603.  
  1604.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1605.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1606.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1607.  
  1608.                 DoIO(ReadBuffer -> SerialRequest);
  1609.  
  1610.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1611.             }
  1612.         }
  1613.     }
  1614.  
  1615.     if(flags & 2)
  1616.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_7WIRE;
  1617.     else
  1618.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_7WIRE;
  1619.  
  1620.     if(flags & 9)
  1621.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_XDISABLED;
  1622.     else
  1623.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_XDISABLED;
  1624.  
  1625.     ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1626.  
  1627.     DoIO(ReadBuffer -> SerialRequest);
  1628.  
  1629.     ThisBuffer -> SerialRequest -> io_SerFlags = ReadBuffer -> SerialRequest -> io_SerFlags;
  1630.     NextBuffer -> SerialRequest -> io_SerFlags = ReadBuffer -> SerialRequest -> io_SerFlags;
  1631. }
  1632.  
  1633.     /* com_setspeed(word speed):
  1634.      *
  1635.      *    Set the transfer speed (in bits/second).
  1636.      */
  1637.  
  1638. VOID
  1639. com_setspeed(word speed)
  1640. {
  1641.     if(ThisBuffer -> IsBusy)
  1642.     {
  1643.         WaitIO(ThisBuffer -> SerialRequest);
  1644.  
  1645.         ThisBuffer -> IsBusy        = FALSE;
  1646.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1647.     }
  1648.  
  1649.     if(ReadBuffer -> IsBusy)
  1650.     {
  1651.         if(!CheckIO(ReadBuffer -> SerialRequest))
  1652.             AbortIO(ReadBuffer -> SerialRequest);
  1653.  
  1654.         WaitIO(ReadBuffer -> SerialRequest);
  1655.  
  1656.         ReadBuffer -> IsBusy        = FALSE;
  1657.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1658.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1659.  
  1660.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1661.  
  1662.         DoIO(ReadBuffer -> SerialRequest);
  1663.  
  1664.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1665.         {
  1666.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1667.  
  1668.             if(Size > 0)
  1669.             {
  1670.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1671.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1672.  
  1673.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1674.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1675.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1676.  
  1677.                 DoIO(ReadBuffer -> SerialRequest);
  1678.  
  1679.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1680.             }
  1681.         }
  1682.     }
  1683.  
  1684.     ReadBuffer -> SerialRequest -> io_Baud = speed;
  1685.  
  1686.     if(parity)
  1687.     {
  1688.         ReadBuffer -> SerialRequest -> io_ReadLen = ReadBuffer -> SerialRequest -> io_WriteLen = 7;
  1689.         ReadBuffer -> SerialRequest -> io_SerFlags |= SERF_PARTY_ON;
  1690.     }
  1691.     else
  1692.     {
  1693.         ReadBuffer -> SerialRequest -> io_ReadLen = ReadBuffer -> SerialRequest -> io_WriteLen = 8;
  1694.         ReadBuffer -> SerialRequest -> io_SerFlags &= ~SERF_PARTY_ON;
  1695.     }
  1696.  
  1697.     ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_SETPARAMS;
  1698.  
  1699.     DoIO(ReadBuffer -> SerialRequest);
  1700.  
  1701.     ThisBuffer -> SerialRequest -> io_Baud        = ReadBuffer -> SerialRequest -> io_Baud;
  1702.     ThisBuffer -> SerialRequest -> io_ReadLen    = ReadBuffer -> SerialRequest -> io_ReadLen;
  1703.     ThisBuffer -> SerialRequest -> io_WriteLen    = ReadBuffer -> SerialRequest -> io_WriteLen;
  1704.     ThisBuffer -> SerialRequest -> io_SerFlags    = ReadBuffer -> SerialRequest -> io_SerFlags;
  1705.  
  1706.     NextBuffer -> SerialRequest -> io_Baud        = ReadBuffer -> SerialRequest -> io_Baud;
  1707.     NextBuffer -> SerialRequest -> io_ReadLen    = ReadBuffer -> SerialRequest -> io_ReadLen;
  1708.     NextBuffer -> SerialRequest -> io_WriteLen    = ReadBuffer -> SerialRequest -> io_WriteLen;
  1709.     NextBuffer -> SerialRequest -> io_SerFlags    = ReadBuffer -> SerialRequest -> io_SerFlags;
  1710. }
  1711.  
  1712.     /* com_putblock(byte *s,word len):
  1713.      *
  1714.      *    Send a data block asynchronously.
  1715.      */
  1716.  
  1717. VOID
  1718. com_putblock(byte *s,word len)
  1719. {
  1720.     struct SerialBuffer *Swap = ThisBuffer;
  1721.  
  1722.     if(ThisBuffer -> IsBusy)
  1723.         WaitIO(ThisBuffer -> SerialRequest);
  1724.     else
  1725.     {
  1726.         if(ThisBuffer -> SerialIndex > ThisBuffer -> SerialBuffer)
  1727.         {
  1728.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1729.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1730.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1731.  
  1732.             DoIO(ThisBuffer -> SerialRequest);
  1733.         }
  1734.     }
  1735.  
  1736.     ThisBuffer -> IsBusy        = FALSE;
  1737.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1738.  
  1739.     ThisBuffer = NextBuffer;
  1740.     NextBuffer = Swap;
  1741.  
  1742.     if(ThisBuffer -> SerialIndex > ThisBuffer -> SerialBuffer)
  1743.     {
  1744.         ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1745.         ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1746.         ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  1747.  
  1748.         DoIO(ThisBuffer -> SerialRequest);
  1749.     }
  1750.  
  1751.     ThisBuffer -> IsBusy        = FALSE;
  1752.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1753.  
  1754.     while(len > 2 * ThisBuffer -> SerialSize)
  1755.     {
  1756.         ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1757.         ThisBuffer -> SerialRequest -> IOSer . io_Data        = s;
  1758.         ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialSize;
  1759.  
  1760.         s    += ThisBuffer -> SerialSize;
  1761.         len    -= ThisBuffer -> SerialSize;
  1762.  
  1763.         DoIO(ThisBuffer -> SerialRequest);
  1764.     }
  1765.  
  1766.     CopyMem(s,ThisBuffer -> SerialBuffer,MIN(len,ThisBuffer -> SerialSize));
  1767.  
  1768.     ThisBuffer -> IsBusy                    = TRUE;
  1769.     ThisBuffer -> SerialIndex                = ThisBuffer -> SerialBuffer + MIN(len,ThisBuffer -> SerialSize);
  1770.     ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1771.     ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  1772.     ThisBuffer -> SerialRequest -> IOSer . io_Length    = MIN(len,ThisBuffer -> SerialSize);
  1773.  
  1774.     len    -= ThisBuffer -> SerialRequest -> IOSer . io_Length;
  1775.     s    += ThisBuffer -> SerialRequest -> IOSer . io_Length;
  1776.  
  1777.     ClrSignal(SIG_SERWRITE);
  1778.     SendIO(ThisBuffer -> SerialRequest);
  1779.  
  1780.     if(len > 0)
  1781.     {
  1782.         CopyMem(s,NextBuffer -> SerialBuffer,len);
  1783.  
  1784.         NextBuffer -> SerialIndex = NextBuffer -> SerialBuffer + len;
  1785.     }
  1786. }
  1787.  
  1788.     /* breakfunc():
  1789.      *
  1790.      *    Cleanup routine for SAS/C.
  1791.      */
  1792.  
  1793. static int
  1794. breakfunc(void)
  1795. {
  1796.     CloseAll();
  1797.  
  1798.     return(1);
  1799. }
  1800.  
  1801.     /* sys_init(VOID):
  1802.      *
  1803.      *    Initialize this driver implementation.
  1804.      */
  1805.  
  1806. VOID
  1807. sys_init(VOID)
  1808. {
  1809.     if(!OpenAll(device,port))
  1810.     {
  1811.         CloseAll();
  1812.  
  1813.         endprog(2);
  1814.     }
  1815.  
  1816.     onbreak(breakfunc);
  1817. }
  1818.  
  1819.     /* sys_reset(VOID):
  1820.      *
  1821.      *    Perform cleanup for this driver implementation.
  1822.      */
  1823.  
  1824. VOID
  1825. sys_reset(VOID)
  1826. {
  1827.     CloseAll();
  1828. }
  1829.  
  1830.     /* sys_idle(VOID):
  1831.      *
  1832.      *    This routine gets called when the system is idle.
  1833.      *    That's a nice one. We are supposed to call the
  1834.      *    system scheduler, etc.
  1835.      */
  1836.  
  1837. VOID
  1838. sys_idle(VOID)
  1839. {
  1840.     ULONG Signals;
  1841.  
  1842.     if(ReadBuffer -> SerialFilled <= 0 && !ReadBuffer -> IsBusy)
  1843.     {
  1844.         ReadBuffer -> IsBusy                    = TRUE;
  1845.         ReadBuffer -> SerialIndex                = ReadBuffer -> SerialBuffer;
  1846.         ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1847.         ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  1848.         ReadBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  1849.  
  1850.         ClrSignal(SIG_SERREAD);
  1851.         SendIO(ReadBuffer -> SerialRequest);
  1852.     }
  1853.  
  1854.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  1855.     TimeRequest -> tr_time . tv_secs    = 1;
  1856.     TimeRequest -> tr_time . tv_micro    = 0;
  1857.  
  1858.     ClrSignal(SIG_TIMER);
  1859.     SendIO(TimeRequest);
  1860.  
  1861.     Signals = Wait(SIG_SERREAD | SIG_SERWRITE | SIG_CONREAD | SIG_WINDOW | SIG_TIMER);
  1862.  
  1863.     if(!(Signals & SIG_TIMER))
  1864.     {
  1865.         if(!CheckIO(TimeRequest))
  1866.             AbortIO(TimeRequest);
  1867.     }
  1868.  
  1869.     WaitIO(TimeRequest);
  1870.  
  1871.     if(Signals & SIG_SERREAD)
  1872.     {
  1873.         WaitIO(ReadBuffer -> SerialRequest);
  1874.  
  1875.         ReadBuffer -> IsBusy        = FALSE;
  1876.         ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1877.         ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  1878.  
  1879.         ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1880.  
  1881.         DoIO(ReadBuffer -> SerialRequest);
  1882.  
  1883.         if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1884.         {
  1885.             LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  1886.  
  1887.             if(Size > 0)
  1888.             {
  1889.                 if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  1890.                     Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1891.  
  1892.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  1893.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  1894.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  1895.  
  1896.                 DoIO(ReadBuffer -> SerialRequest);
  1897.  
  1898.                 ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  1899.             }
  1900.         }
  1901.     }
  1902.  
  1903.     if(Signals & SIG_SERWRITE)
  1904.     {
  1905.         struct SerialBuffer *Swap = ThisBuffer;
  1906.  
  1907.         WaitIO(ThisBuffer -> SerialRequest);
  1908.  
  1909.         ThisBuffer -> IsBusy        = FALSE;
  1910.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1911.  
  1912.         ThisBuffer = NextBuffer;
  1913.         NextBuffer = Swap;
  1914.     }
  1915.  
  1916.     if(Signals & SIG_CONREAD)
  1917.     {
  1918.         WaitIO(ConsoleReadRequest);
  1919.  
  1920.         ConsoleReady = TRUE;
  1921.     }
  1922.  
  1923.     if(Signals & SIG_WINDOW)
  1924.         WindowReady = TRUE;
  1925. }
  1926.  
  1927.     /* com_outfull(VOID):
  1928.      *
  1929.      *    Return number of bytes still to be transferred.
  1930.      */
  1931.  
  1932. int
  1933. com_outfull(VOID)
  1934. {
  1935.     return(ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer + NextBuffer -> SerialIndex - NextBuffer -> SerialBuffer);
  1936. }
  1937.  
  1938.     /* carrier(VOID):
  1939.      *
  1940.      *    Return current carrier status.
  1941.      */
  1942.  
  1943. int
  1944. carrier(VOID)
  1945. {
  1946.     if(nocarrier)
  1947.         return(1);
  1948.     else
  1949.     {
  1950.         if(!ThisBuffer -> IsBusy)
  1951.         {
  1952.             ThisBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1953.  
  1954.             DoIO(ThisBuffer -> SerialRequest);
  1955.  
  1956.             if(ThisBuffer -> SerialRequest -> io_Status & CIAF_COMCD)
  1957.                 return(0);
  1958.             else
  1959.                 return(1);
  1960.         }
  1961.         else
  1962.         {
  1963.             NextBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  1964.  
  1965.             DoIO(NextBuffer -> SerialRequest);
  1966.  
  1967.             if(NextBuffer -> SerialRequest -> io_Status & CIAF_COMCD)
  1968.                 return(0);
  1969.             else
  1970.                 return(1);
  1971.         }
  1972.     }
  1973. }
  1974.  
  1975.     /* com_flush(VOID):
  1976.      *
  1977.      *    Make sure all pending data gets written.
  1978.      */
  1979.  
  1980. VOID
  1981. com_flush(VOID)
  1982. {
  1983.     if(ThisBuffer -> IsBusy)
  1984.     {
  1985.         WaitIO(ThisBuffer -> SerialRequest);
  1986.  
  1987.         ThisBuffer -> IsBusy        = FALSE;
  1988.         ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  1989.     }
  1990.  
  1991.     if(NextBuffer -> SerialIndex > NextBuffer -> SerialBuffer)
  1992.     {
  1993.         NextBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  1994.         NextBuffer -> SerialRequest -> IOSer . io_Data        = NextBuffer -> SerialBuffer;
  1995.         NextBuffer -> SerialRequest -> IOSer . io_Length    = NextBuffer -> SerialIndex - NextBuffer -> SerialBuffer;
  1996.  
  1997.         DoIO(NextBuffer -> SerialRequest);
  1998.  
  1999.         NextBuffer -> SerialIndex = NextBuffer -> SerialBuffer;
  2000.     }
  2001. }
  2002.  
  2003.     /* com_putbyte(byte c):
  2004.      *
  2005.      *    Transmit a single byte, queueing it if necessary.
  2006.      */
  2007.  
  2008. VOID
  2009. com_putbyte(byte c)
  2010. {
  2011.     if(ThisBuffer -> IsBusy)
  2012.     {
  2013.         if(NextBuffer -> SerialIndex + 1 >= NextBuffer -> SerialTop)
  2014.         {
  2015.             struct SerialBuffer *Swap = ThisBuffer;
  2016.  
  2017.             WaitIO(ThisBuffer -> SerialRequest);
  2018.  
  2019.             ThisBuffer -> IsBusy        = FALSE;
  2020.             ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  2021.  
  2022.             ThisBuffer = NextBuffer;
  2023.             NextBuffer = Swap;
  2024.  
  2025.             ThisBuffer -> IsBusy                    = TRUE;
  2026.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  2027.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  2028.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  2029.  
  2030.             ClrSignal(SIG_SERWRITE);
  2031.             SendIO(ThisBuffer -> SerialRequest);
  2032.         }
  2033.  
  2034.         *NextBuffer -> SerialIndex++ = c;
  2035.     }
  2036.     else
  2037.     {
  2038.         if(ThisBuffer -> SerialIndex + 1 < ThisBuffer -> SerialTop)
  2039.         {
  2040.             *ThisBuffer -> SerialIndex++ = c;
  2041.  
  2042.             ThisBuffer -> IsBusy                    = TRUE;
  2043.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  2044.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  2045.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  2046.  
  2047.             ClrSignal(SIG_SERWRITE);
  2048.             SendIO(ThisBuffer -> SerialRequest);
  2049.         }
  2050.         else
  2051.         {
  2052.             ThisBuffer -> IsBusy                    = TRUE;
  2053.             ThisBuffer -> SerialRequest -> IOSer . io_Command    = CMD_WRITE;
  2054.             ThisBuffer -> SerialRequest -> IOSer . io_Data        = ThisBuffer -> SerialBuffer;
  2055.             ThisBuffer -> SerialRequest -> IOSer . io_Length    = ThisBuffer -> SerialIndex - ThisBuffer -> SerialBuffer;
  2056.  
  2057.             ClrSignal(SIG_SERWRITE);
  2058.             SendIO(ThisBuffer -> SerialRequest);
  2059.  
  2060.             *NextBuffer -> SerialIndex++ = c;
  2061.         }
  2062.     }
  2063. }
  2064.  
  2065.     /* com_purge(VOID):
  2066.      *
  2067.      *    Clear the read/write buffers.
  2068.      */
  2069.  
  2070. VOID
  2071. com_purge(VOID)
  2072. {
  2073.     if(ThisBuffer -> IsBusy)
  2074.     {
  2075.         if(!CheckIO(ThisBuffer -> SerialRequest))
  2076.             AbortIO(ThisBuffer -> SerialRequest);
  2077.  
  2078.         WaitIO(ThisBuffer -> SerialRequest);
  2079.     }
  2080.  
  2081.     ThisBuffer -> IsBusy        = FALSE;
  2082.     ThisBuffer -> SerialIndex    = ThisBuffer -> SerialBuffer;
  2083.  
  2084.     NextBuffer -> IsBusy        = FALSE;
  2085.     NextBuffer -> SerialIndex    = NextBuffer -> SerialBuffer;
  2086.  
  2087.     if(ReadBuffer -> IsBusy)
  2088.     {
  2089.         if(!CheckIO(ReadBuffer -> SerialRequest))
  2090.             AbortIO(ReadBuffer -> SerialRequest);
  2091.  
  2092.         WaitIO(ReadBuffer -> SerialRequest);
  2093.     }
  2094.  
  2095.     ReadBuffer -> IsBusy        = FALSE;
  2096.     ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2097.     ReadBuffer -> SerialFilled    = 0;
  2098.  
  2099.     ThisBuffer -> SerialRequest -> IOSer . io_Command = CMD_CLEAR;
  2100.     DoIO(ThisBuffer -> SerialRequest);
  2101. }
  2102.  
  2103.     /* com_dump(VOID):
  2104.      *
  2105.      *    Wait for asynchronous write request to terminate.
  2106.      */
  2107.  
  2108. VOID
  2109. com_dump(VOID)
  2110. {
  2111.     com_flush();
  2112. }
  2113.  
  2114.     /* com_getbyte(VOID):
  2115.      *
  2116.      *    Read a single byte from the serial line. If not available,
  2117.      *    return EOF.
  2118.      */
  2119.  
  2120. int
  2121. com_getbyte(VOID)
  2122. {
  2123.     int Result;
  2124.  
  2125.     if(ReadBuffer -> SerialFilled <= 0)
  2126.     {
  2127.         if(ReadBuffer -> IsBusy)
  2128.         {
  2129.             if(!CheckIO(ReadBuffer -> SerialRequest))
  2130.                 return(EOF);
  2131.             else
  2132.                 WaitIO(ReadBuffer -> SerialRequest);
  2133.  
  2134.             ReadBuffer -> IsBusy        = FALSE;
  2135.             ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2136.             ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2137.  
  2138.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  2139.  
  2140.             DoIO(ReadBuffer -> SerialRequest);
  2141.  
  2142.             if(ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2143.             {
  2144.                 LONG Size = ReadBuffer -> SerialSize - ReadBuffer -> SerialFilled;
  2145.  
  2146.                 if(Size > 0)
  2147.                 {
  2148.                     if(Size > ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2149.                         Size = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2150.  
  2151.                     ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2152.                     ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer + ReadBuffer -> SerialFilled;
  2153.                     ReadBuffer -> SerialRequest -> IOSer . io_Length    = Size;
  2154.  
  2155.                     DoIO(ReadBuffer -> SerialRequest);
  2156.  
  2157.                     ReadBuffer -> SerialFilled += ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2158.                 }
  2159.             }
  2160.         }
  2161.         else
  2162.         {
  2163.             ReadBuffer -> SerialRequest -> IOSer . io_Command = SDCMD_QUERY;
  2164.  
  2165.             DoIO(ReadBuffer -> SerialRequest);
  2166.  
  2167.             if(!ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2168.                 return(EOF);
  2169.             else
  2170.             {
  2171.                 ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2172.                 ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  2173.                 ReadBuffer -> SerialRequest -> IOSer . io_Length    = MIN(ReadBuffer -> SerialRequest -> IOSer . io_Actual,ReadBuffer -> SerialSize);
  2174.  
  2175.                 DoIO(ReadBuffer -> SerialRequest);
  2176.  
  2177.                 if(!ReadBuffer -> SerialRequest -> IOSer . io_Actual)
  2178.                     return(EOF);
  2179.                 else
  2180.                 {
  2181.                     ReadBuffer -> SerialFilled    = ReadBuffer -> SerialRequest -> IOSer . io_Actual;
  2182.                     ReadBuffer -> SerialIndex    = ReadBuffer -> SerialBuffer;
  2183.                 }
  2184.             }
  2185.         }
  2186.     }
  2187.  
  2188.     Result = *ReadBuffer -> SerialIndex++;
  2189.  
  2190.     ReadBuffer -> SerialFilled--;
  2191.  
  2192.     if(ReadBuffer -> SerialFilled <= 0)
  2193.     {
  2194.         ReadBuffer -> IsBusy                    = TRUE;
  2195.         ReadBuffer -> SerialIndex                = ReadBuffer -> SerialBuffer;
  2196.  
  2197.         ReadBuffer -> SerialRequest -> IOSer . io_Command    = CMD_READ;
  2198.         ReadBuffer -> SerialRequest -> IOSer . io_Data        = ReadBuffer -> SerialBuffer;
  2199.         ReadBuffer -> SerialRequest -> IOSer . io_Length    = 1;
  2200.  
  2201.         ClrSignal(SIG_SERREAD);
  2202.         SendIO(ReadBuffer -> SerialRequest);
  2203.     }
  2204.  
  2205.     return(Result);
  2206. }
  2207.  
  2208.     /* setstamp(STRPTR Name,LONG Time):
  2209.      *
  2210.      *    Set time/date of a file.
  2211.      */
  2212.  
  2213. VOID
  2214. setstamp(char *Name,long Time)
  2215. {
  2216.     struct DateStamp    Date;
  2217.     ULONG            Seconds;
  2218.  
  2219.     DB(kprintf("setstamp |%s| %ld\n",Name,Time));
  2220.  
  2221.         /* Translate it into an Amiga date. */
  2222.  
  2223.     if(Time > GMT_Offset)
  2224.         Seconds = Time - GMT_Offset;
  2225.     else
  2226.         Seconds = 0;
  2227.  
  2228.     Date . ds_Days        = Seconds / (24 * 60 * 60);
  2229.     Date . ds_Minute    = (Seconds % (24 * 60 * 60)) / 60;
  2230.     Date . ds_Tick        = (Seconds % 60) * TICKS_PER_SECOND;
  2231.  
  2232.     SetFileDate(Name,&Date);
  2233. }
  2234.  
  2235.     /* freespace(STRPTR DrivePath):
  2236.      *
  2237.      *    Get free disk space for specified drive.
  2238.      */
  2239.  
  2240. long
  2241. freespace(char *DrivePath)
  2242. {
  2243.     struct DevProc    *DevProc = GetDeviceProc(DrivePath,NULL);
  2244.     struct DosList    *DosList;
  2245.     BOOL         GoodDevice = FALSE;
  2246.     LONG         Size = (LONG)((ULONG)~0 >> 2);
  2247.  
  2248.     if(!DrivePath)
  2249.         DrivePath = "";
  2250.  
  2251.     DB(kprintf("freespace |%s|\n",DrivePath));
  2252.  
  2253.     if(DosList = LockDosList(LDF_DEVICES | LDF_READ))
  2254.     {
  2255.         while(DosList = NextDosEntry(DosList,LDF_DEVICES))
  2256.         {
  2257.             if(DosList -> dol_Task == DevProc -> dvp_Port)
  2258.             {
  2259.                 struct FileSysStartupMsg *FSSM = (struct FileSysStartupMsg *)BADDR(DosList -> dol_misc . dol_handler . dol_Startup);
  2260.  
  2261.                 if(TypeOfMem(FSSM))
  2262.                 {
  2263.                     struct DosEnvec *DosEnvec = (struct DosEnvec *)BADDR(FSSM -> fssm_Environ);
  2264.                     STRPTR Name = (STRPTR)BADDR(FSSM -> fssm_Device);
  2265.  
  2266.                     if(TypeOfMem(DosEnvec) && TypeOfMem(Name))
  2267.                     {
  2268.                         if(Name[0] > 0 && !Name[(WORD)Name[0] + 1])
  2269.                         {
  2270.                             struct IOStdReq __aligned IORequest;
  2271.  
  2272.                             if(!OpenDevice(Name + 1,FSSM -> fssm_Unit,&IORequest,FSSM -> fssm_Unit))
  2273.                             {
  2274.                                 CloseDevice(&IORequest);
  2275.  
  2276.                                 if(DosEnvec -> de_TableSize > 0 && DosEnvec -> de_LowCyl <= DosEnvec -> de_HighCyl)
  2277.                                     GoodDevice = TRUE;
  2278.                             }
  2279.                         }
  2280.                     }
  2281.                 }
  2282.             }
  2283.         }
  2284.  
  2285.         UnLockDosList(LDF_DEVICES | LDF_READ);
  2286.     }
  2287.  
  2288.     FreeDeviceProc(DevProc);
  2289.  
  2290.     if(GoodDevice)
  2291.     {
  2292.         struct InfoData *InfoData;
  2293.  
  2294.         if(InfoData = (struct InfoData *)AllocVec(sizeof(struct InfoData),MEMF_ANY | MEMF_PUBLIC))
  2295.         {
  2296.             UBYTE NewName[256],*Index;
  2297.             BPTR FileLock;
  2298.  
  2299.             memcpy(NewName,DrivePath,255);
  2300.  
  2301.             NewName[255] = 0;
  2302.  
  2303.             Index = PathPart(NewName);
  2304.  
  2305.             *Index = 0;
  2306.  
  2307.             FileLock = Lock(NewName,ACCESS_READ);
  2308.  
  2309.             if(FileLock)
  2310.             {
  2311.                 if(Info(FileLock,InfoData))
  2312.                     Size = InfoData -> id_BytesPerBlock * (InfoData -> id_NumBlocks - InfoData -> id_NumBlocksUsed);
  2313.  
  2314.                 UnLock(FileLock);
  2315.             }
  2316.  
  2317.             FreeVec(InfoData);
  2318.         }
  2319.     }
  2320.  
  2321.     return(Size);
  2322. }
  2323.  
  2324.     /* ffirst(char *FileSpec):
  2325.      *
  2326.      *    Return name of first file matching the given specs.
  2327.      */
  2328.  
  2329. char *
  2330. ffirst(char *filespec)
  2331. {
  2332.     AnchorUsed = TRUE;
  2333.  
  2334.     DB(kprintf("ffirst |%s|\n",filespec));
  2335.  
  2336.     if(MatchFirst(filespec,Anchor))
  2337.         return(NULL);
  2338.     else
  2339.         return((char *)Anchor -> ap_Buf);
  2340. }
  2341.  
  2342.     /* fnext(VOID):
  2343.      *
  2344.      *    Return name of next file matching the given specs.
  2345.      */
  2346.  
  2347. char *
  2348. fnext(VOID)
  2349. {
  2350.     AnchorUsed = TRUE;
  2351.  
  2352.     DB(kprintf("fnext\n"));
  2353.  
  2354.     if(MatchNext(Anchor))
  2355.         return(NULL);
  2356.     else
  2357.         return((char *)Anchor -> ap_Buf);
  2358. }
  2359.  
  2360.     /* time(time_t *timeptr):
  2361.      *
  2362.      *    Get the current time.
  2363.      */
  2364.  
  2365. time_t
  2366. time(time_t *timeptr)
  2367. {
  2368.     struct timeval    Now;
  2369.     time_t        CurrentTime;
  2370.  
  2371.     DB(kprintf("time 0x%08lx\n",timeptr));
  2372.  
  2373.         /* If the timer is already available,
  2374.          * just read the time. Otherwise, open what
  2375.          * we need to tell the time.
  2376.          */
  2377.  
  2378.     if(TimerBase)
  2379.         GetSysTime(&Now);
  2380.     else
  2381.         UpdateTime(&Now);
  2382.  
  2383.         /* Determine the current time, taking the time
  2384.          * zone into account.
  2385.          */
  2386.  
  2387.     CurrentTime = (time_t)(Now . tv_secs + GMT_Offset);
  2388.  
  2389.     if(timeptr)
  2390.         *timeptr = CurrentTime;
  2391.  
  2392.     return(CurrentTime);
  2393. }
  2394.  
  2395.     /* localtime(const time_t *t):
  2396.      *
  2397.      *    Convert UTC into local time.
  2398.      */
  2399.  
  2400. struct tm *
  2401. localtime(const time_t *t)
  2402. {
  2403.     STATIC struct tm Time;
  2404.  
  2405.     ULONG            Seconds,
  2406.                 Delta;
  2407.     struct ClockData    ClockData;
  2408.     BOOL            CloseIt = FALSE;
  2409.  
  2410.     DB(kprintf("localtime 0x%08lx\n",t));
  2411.  
  2412.         /* We need utility.library for the date conversion. */
  2413.  
  2414.     if(!UtilityBase)
  2415.     {
  2416.         if(UtilityBase = OpenLibrary("utility.library",37))
  2417.             CloseIt = TRUE;
  2418.     }
  2419.  
  2420.         /* Any luck? */
  2421.  
  2422.     if(!UtilityBase)
  2423.     {
  2424.         memset(&Time,0,sizeof(struct tm));
  2425.  
  2426.         return(&Time);
  2427.     }
  2428.  
  2429.         /* Update the time data. */
  2430.  
  2431.     if(!TimerBase)
  2432.         UpdateTime(NULL);
  2433.  
  2434.         /* Add the offset. */
  2435.  
  2436.     if(*t < GMT_Offset)
  2437.         Seconds = 0;
  2438.     else
  2439.         Seconds = (ULONG)*t - GMT_Offset;
  2440.  
  2441.         /* Convert the seconds into time data. */
  2442.  
  2443.     Amiga2Date(Seconds,&ClockData);
  2444.  
  2445.         /* Convert the time data. */
  2446.  
  2447.     Time . tm_sec    = ClockData . sec;
  2448.     Time . tm_min    = ClockData . min;
  2449.     Time . tm_hour    = ClockData . hour;
  2450.     Time . tm_mday    = ClockData . mday;
  2451.     Time . tm_mon    = ClockData . month - 1;
  2452.     Time . tm_year    = ClockData . year - 1900;
  2453.     Time . tm_wday    = ClockData . wday;
  2454.  
  2455.         /* No daylight savings time info is provided. */
  2456.  
  2457.     Time . tm_isdst = 0;
  2458.  
  2459.         /* We will need to fill in the yday entry. */
  2460.  
  2461.     ClockData . mday    = 1;
  2462.     ClockData . month    = 1;
  2463.  
  2464.     Delta = Date2Amiga(&ClockData);
  2465.  
  2466.     Time . tm_yday = (Seconds - Delta) / (24 * 60 * 60) + 1;
  2467.  
  2468.         /* Clean up if necessary. */
  2469.  
  2470.     if(CloseIt)
  2471.     {
  2472.         CloseLibrary(UtilityBase);
  2473.  
  2474.         UtilityBase = NULL;
  2475.     }
  2476.  
  2477.     return(&Time);
  2478. }
  2479.  
  2480.     /* stat(const char *file,struct stat *st):
  2481.      *
  2482.      *    Get information on a file.
  2483.      */
  2484.  
  2485. int
  2486. stat(const char *file,struct stat *st)
  2487. {
  2488.     BPTR FileLock;
  2489.  
  2490.     DB(kprintf("stat |%s| 0%08lx\n",file,st));
  2491.  
  2492.         /* Try to get a lock on the file. */
  2493.  
  2494.     if(FileLock = Lock((STRPTR)file,ACCESS_READ))
  2495.     {
  2496.         STATIC char    Volume[256],
  2497.                 Comment[80];
  2498.  
  2499.         struct FileInfoBlock __aligned    FileInfo;
  2500.         struct InfoData __aligned    InfoData;
  2501.  
  2502.             /* Get information on file and filing system. */
  2503.  
  2504.         if(Examine(FileLock,&FileInfo) && Info(FileLock,&InfoData))
  2505.         {
  2506.             unsigned short mode = 0;
  2507.  
  2508.                 /* Try to get the name of the volume. */
  2509.  
  2510.             if(!NameFromLock(FileLock,Volume,256))
  2511.                 Volume[0] = 0;
  2512.             else
  2513.             {
  2514.                 WORD i;
  2515.  
  2516.                     /* Chop off everything after the colon. */
  2517.  
  2518.                 for(i = 0 ; i < 256 ; i++)
  2519.                 {
  2520.                     if(Volume[i] == ':')
  2521.                     {
  2522.                         Volume[i + 1] = 0;
  2523.  
  2524.                         break;
  2525.                     }
  2526.                 }
  2527.             }
  2528.  
  2529.             UnLock(FileLock);
  2530.  
  2531.                 /* Build the protection bits. */
  2532.  
  2533.             if(!(FileInfo . fib_Protection & FIBF_EXECUTE))
  2534.                 mode |= S_IEXECUTE;
  2535.  
  2536.             if(!(FileInfo . fib_Protection & FIBF_DELETE))
  2537.                 mode |= S_IDELETE;
  2538.  
  2539.             if(!(FileInfo . fib_Protection & FIBF_READ))
  2540.                 mode |= S_IREAD;
  2541.  
  2542.             if(!(FileInfo . fib_Protection & FIBF_WRITE))
  2543.                 mode |= S_IWRITE;
  2544.  
  2545.             if(!(FileInfo . fib_Protection & FIBF_ARCHIVE))
  2546.                 mode |= S_IARCHIVE;
  2547.  
  2548.             if(FileInfo . fib_Protection & FIBF_PURE)
  2549.                 mode |= S_IPURE;
  2550.  
  2551.             if(FileInfo . fib_Protection & FIBF_SCRIPT)
  2552.                 mode |= S_ISCRIPT;
  2553.  
  2554.                 /* Keep the comment. */
  2555.  
  2556.             strcpy(Comment,FileInfo . fib_Comment);
  2557.  
  2558.                 /* Fix the time if necessary. */
  2559.  
  2560.             if(!TimerBase)
  2561.                 UpdateTime(NULL);
  2562.  
  2563.                 /* Fill in the data. */
  2564.  
  2565.             st -> st_mode    = mode;
  2566.             st -> st_ino    = FileInfo . fib_DiskKey;
  2567.             st -> st_dev    = InfoData . id_DiskType;
  2568.             st -> st_rdev    = Volume;
  2569.             st -> st_nlink    = FileInfo . fib_DirEntryType == ST_SOFTLINK || FileInfo . fib_DirEntryType == ST_LINKDIR || FileInfo . fib_DirEntryType == ST_LINKFILE;
  2570.             st -> st_uid    = FileInfo . fib_OwnerUID;
  2571.             st -> st_gid    = FileInfo . fib_OwnerGID;
  2572.             st -> st_size    = FileInfo . fib_Size;
  2573.             st -> st_atime    = GMT_Offset + (FileInfo . fib_Date . ds_Days * 24 * 60 + FileInfo . fib_Date . ds_Minute) * 60 + FileInfo . fib_Date . ds_Tick / TICKS_PER_SECOND;
  2574.             st -> st_mtime    = st -> st_atime;
  2575.             st -> st_ctime    = st -> st_atime;
  2576.             st -> st_type    = FileInfo . fib_DirEntryType;
  2577.             st -> st_comment= Comment;
  2578.  
  2579.                 /* Success. */
  2580.  
  2581.             return(0);
  2582.         }
  2583.  
  2584.         UnLock(FileLock);
  2585.     }
  2586.  
  2587.         /* What else should I choose? */
  2588.  
  2589.     errno = _OSERR = EIO;
  2590.  
  2591.     return(-1);
  2592. }
  2593.